package com.lemon.exam.common.web;

import com.lemon.exam.common.util.CriteriaUtil;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Getter;
import lombok.Setter;
import org.assertj.core.util.Arrays;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.data.relational.core.query.Criteria;
import org.springframework.data.relational.core.query.Query;
import reactor.core.publisher.Mono;
import reactor.core.scheduler.Schedulers;

import java.util.Map;

/**
 * 公共的请求参数
 *
 * @author Lemon
 * @since 2025/3/15 12:35
 */
@Getter
@Setter
@Schema(name = "请求参数", description = "通用查询参数")
public class Param {
    @Schema(description = "分页参数-页码")
    private Integer pageNum = 1;

    @Schema(description = "分页参数-数量")
    private Integer pageSize = 10;

    @Schema(description = "排序参数-正序")
    private String[] asc;

    @Schema(description = "排序参数-倒序")
    private String[] desc;

    @Schema(description = "查询参数")
    private Map<String, Object> param;

    /**
     * 获取页码参数
     *
     * @return
     */
    public Integer getPageNum() {
        return pageNum - 1;
    }

    /**
     * 获取排序参数
     *
     * @return 排序信息
     */
    public Mono<Sort> getSort() {
        return Mono.fromCallable(() -> {
            if (Arrays.isNullOrEmpty(asc) && Arrays.isNullOrEmpty(desc)) {
                return Sort.unsorted();
            } else if (Arrays.isNullOrEmpty(asc)) {
                return Sort.by(Sort.Direction.DESC, desc);
            } else if (Arrays.isNullOrEmpty(desc)) {
                return Sort.by(Sort.Direction.ASC, asc);
            } else {
                return Sort.by(Sort.Direction.DESC, desc)
                        .and(Sort.by(Sort.Direction.ASC, asc));
            }
        }).subscribeOn(Schedulers.parallel());
    }

    /**
     * 获取分页参数
     *
     * @return 分页信息和排序信息
     */
    public Mono<PageRequest> getPageRequest() {
        return getSort().map(sort -> PageRequest.of(getPageNum(), getPageSize(), sort));
    }

    /**
     * 获取查询参数
     *
     * @return 查询条件
     */
    public Mono<Query> getQuery() {
        return Mono.zip(getCriteria(), getPageRequest()).map(tuple -> Query.query(tuple.getT1()).with(tuple.getT2()));
    }

    /**
     * 获取查询条件
     *
     * @return 查询条件
     */
    public Mono<Criteria> getCriteria() {
        return CriteriaUtil.toCriteria(param);
    }
}
